#include "GraphWidgetObject.h"

#include <limits>
#include <typeinfo>
#include <QDebug>

GraphWidgetObject::GraphWidgetObject(QColor color, float width, QString title) :
    objectPen(QPen(QBrush(color), width)),
    name(title)
{
    this->setupBounds();
}

GraphWidgetObject::GraphWidgetObject(const GraphWidgetObject &gwo) :
    points(gwo.points),
    objectPen(gwo.objectPen),
    xMin(gwo.xMin),
    yMin(gwo.yMin),
    xMax(gwo.xMax),
    yMax(gwo.yMax),
    name(gwo.name)
{
}

float GraphWidgetObject::minX()
{
    return xMin;
}

float GraphWidgetObject::minY()
{
    return yMin;
}

float GraphWidgetObject::maxX()
{
    return xMax;
}

float GraphWidgetObject::maxY()
{
    return yMax;
}

float GraphWidgetObject::width()
{
    return objectPen.widthF();
}

QColor GraphWidgetObject::color()
{
    return objectPen.color();
}

QPen GraphWidgetObject::pen()
{
    return objectPen;
}

QString GraphWidgetObject::title()
{
    return name;
}

void GraphWidgetObject::setWidth(float width)
{
    objectPen.setWidthF(width);
}

void GraphWidgetObject::setColor(QColor color)
{
    objectPen.setColor(color);
}

void GraphWidgetObject::setupBounds()
{
    xMin = std::numeric_limits<float>::max();
    yMin = std::numeric_limits<float>::max();
    xMax = std::numeric_limits<float>::min();
    yMax = std::numeric_limits<float>::min();
}

void GraphWidgetObject::adjustBoundsToPoint(QPointF point)
{
    if (point.x() > xMax) {
        xMax = point.x();
    }
    if (point.x() < xMin) {
        xMin = point.x();
    }
    if (point.y() > yMax) {
        yMax = point.y();
    }
    if (point.y() < yMin) {
        yMin = point.y();
    }
}

void GraphWidgetObject::appendPoint(QPointF point)
{
    points.append(point);
    this->adjustBoundsToPoint(point);
}

QVector<float> GraphWidgetObject::xValues()
{
    QVector<float> xValues;
    foreach (QPointF point, points) {
        xValues.append(point.x());
    }

    return xValues;
}

QVector<float> GraphWidgetObject::yValues()
{
    QVector<float> yValues;
    foreach (QPointF point, points) {
        yValues.append(point.y());
    }

    return yValues;
}

QVector<QPointF> GraphWidgetObject::values()
{
    return points;
}

float GraphWidgetObject::yValueAt(float xValue)
{
    QVector<float> yValues = this->yValuesAt(xValue);
    if (yValues.isEmpty())
        return 0;
    return yValues.first();
}

QVector<float> GraphWidgetObject::yValuesAt(float xValue)
{
    QVector<QLineF> segments;
    for (int i = 1; i < points.count(); i++) {
        QPointF first = points[i - 1];
        QPointF second = points[i];

        if (first.x() <= xValue && xValue <= second.x()) {
            QLineF segment(first, second);
            segments.append(segment);
        }
    }

    QVector<float> yValues;

    foreach (QLineF segment, segments) {
        float m = segment.dy() / segment.dx();
        float b = segment.y1() - segment.x1() * m;
        float yValue = m * xValue + b;
        yValues.append(yValue);
    }

    return yValues;
}

QString GraphWidgetObject::type()
{
    QString className(typeid(*this).name());
    className.replace(QRegExp("^\\d*"), "");
    return className;
}

void GraphWidgetObject::draw()
{
    this->draw(objectPen);
}

void GraphWidgetObject::select(QPen pen)
{
    this->draw(pen);
}
